package org.example.service.imp;

import org.example.service.FollowService;
import org.example.util.CommonParam;
import org.example.vo.FollowVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class FollowServiceImp implements FollowService {
    @Autowired
    private RedisTemplate<String,Object> redisTemplate;
    /**
     * 完整的关注key  follow-entityType-userid    value（entityids  如果需要排序 就用zset）
     */
    private static final String FOLLOW_KEY = "follow-";
    private static final String STATIC_SEPARATOR= "-";
    /**
     * 用户的粉丝 帖子的粉丝 ... 都是entityType不同
     * 完整的粉丝key  fans-entityType-entityId  value（userIds  如果需要排序 就用zset）
     */
    private static final String FANS_KEY = "fans-";

    /**
     * 查看一个entityId是否是关注过的
     * @param userid
     * @param entityType
     * @param entityId
     * @return
     */
    public boolean isFollow(int userid,int entityType,int entityId){
        String followKey = FOLLOW_KEY+entityType+STATIC_SEPARATOR+userid;
        Set<Object> range = redisTemplate.opsForZSet().range(followKey, 0, Integer.MAX_VALUE);
        if (range.contains(entityId)) return true;
        else return false;
    }

    /**
     * 我关注了他(将他放进我的关注容器中)  那我就是他的粉丝(将我放进他的粉丝容器中)  这两个是一起的 事务
     * @param userid
     * @param entityType 1-帖子 2评论 3用户
     * @param entityId
     */
    public void follow(int userid,int entityType,int entityId){
        String followKey = FOLLOW_KEY+entityType+STATIC_SEPARATOR+userid;
        String fansKey = FANS_KEY+entityType+STATIC_SEPARATOR+entityId;
        redisTemplate.execute(new SessionCallback<Object>() {
            @Override
            public <K, V> Object execute(RedisOperations<K, V> redisOperations) throws DataAccessException {
                redisOperations.multi();

                redisTemplate.opsForZSet().add(followKey,entityId,System.currentTimeMillis());
                redisTemplate.opsForZSet().add(fansKey,userid,System.currentTimeMillis());
                redisOperations.exec();
                return null;
            }
        });
    }
    public void unFollow(int userid,int entityType,int entityId){
        String followKey = FOLLOW_KEY+entityType+STATIC_SEPARATOR+userid;
        String fansKey = FANS_KEY+entityType+STATIC_SEPARATOR+entityId;
        redisTemplate.execute(new SessionCallback<Object>() {
            @Override
            public <K, V> Object execute(RedisOperations<K, V> redisOperations) throws DataAccessException {
                redisOperations.multi();
                redisTemplate.opsForZSet().remove(followKey,entityId);
                redisTemplate.opsForZSet().remove(fansKey,userid);
                redisOperations.exec();
                return null;
            }
        });
    }

    public int getUserFollowCount(int userid,int entityType){
        String followKey = FOLLOW_KEY+entityType+STATIC_SEPARATOR+userid;
        Set<Object> range = redisTemplate.opsForZSet().range(followKey, 0, Integer.MAX_VALUE);
        return range.size();
    }
    public int getUserFansCount(int userid,int entityType){
        String fansKey = FANS_KEY+entityType+STATIC_SEPARATOR+userid;
        Set<Object> range = redisTemplate.opsForZSet().range(fansKey, 0, Integer.MAX_VALUE);
        return range.size();
    }

    /**
     * 用户关注的
     * @param entityType
     * @param userId
     * @return
     */
    public FollowVO getFollowOrFans(int entityType,int userId,String symbol){
        String key = null;
        if (symbol!=null && symbol.equals(CommonParam.FOLLOW_STATUS)){
            key = FOLLOW_KEY+entityType+STATIC_SEPARATOR+userId;
        }else if (symbol!=null && symbol.equals(CommonParam.FANS_STATUS)){
            key = FANS_KEY+entityType+STATIC_SEPARATOR+userId;
        }
        Set<ZSetOperations.TypedTuple<Object>> typedTuples = redisTemplate.opsForZSet().reverseRangeWithScores(key, 0, Integer.MAX_VALUE);
        FollowVO followVO = new FollowVO();
        List<Object> ids = new ArrayList<>();
        Map<Integer,Date> followTime = new HashMap<>();
        for (ZSetOperations.TypedTuple<Object> temp:typedTuples){
            ids.add(temp.getValue());
            double time = temp.getScore();
            followTime.put((Integer) temp.getValue(),new Date((long)time));
        }
        followVO.setFollowUserIds(ids);
        followVO.setFollowUserTime(followTime);
        return followVO;
    }


}
